package com.example.common.widget;

import android.content.Context;
import android.database.Cursor;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;

import android.os.Bundle;
import android.provider.MediaStore;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.CursorLoader;
import androidx.loader.content.Loader;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.example.common.R;
import com.example.common.widget.recycler.RecyclerAdapter;

import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;

/**
 * TODO: document your custom view class.
 */
public class GalleryView extends RecyclerView {
    private static final String TAG = "GalleyView";

    private static final int LOADER_ID = 0x0100;
    private static final int MAX_IMAGE_COUNT = 9;   // 最大的选中图片数量
    private static final int MIN_IMAGE_FILE_SIZE = 10 * 1024;   // 最小的图片大小为10kb
    private LoaderCallback mLoaderCallback = new LoaderCallback();
    private Adapter mAdapter = new Adapter();
    private SelectedChangedListener mListener;


    // 这里的list不断的发生长度的变化，所以就不用ArrayList，使用LinkedList减少性能消耗
    private List<Image> mSelectedImages = new LinkedList<>();

    public GalleryView(Context context) {
        super(context);
        init();
    }

    public GalleryView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public GalleryView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        // 一般来说继承了RecycleView都会使用这个方法
        setLayoutManager(new GridLayoutManager(getContext(), 4));
        // 把mAdapter设置到RecycleView
        setAdapter(mAdapter);
        mAdapter.setListener(new RecyclerAdapter.AdapterListenerImpl<Image>() {
            @Override
            public void onItemClick(RecyclerAdapter.ViewHolder holder, Image image) {
                // cell点击操作，如果我们的点击是允许的，那么更新对应的Cell的状态
                // 然后更新界面，同理：如果不能运行点击（已经达到最大的选中数量），就不用刷新界面
                if (onItemSelectClick(image)) {
                    holder.updateData(image);
                }
            }
        });
    }

    /**
     * 初始化方法
     * @param loaderManager Loader管理器
     * @return 任何一个LOADER_ID，用于销毁loader
     */
    public int setup(LoaderManager loaderManager, SelectedChangedListener listener) {
        mListener = listener;
        loaderManager.initLoader(LOADER_ID, null, mLoaderCallback);
        return LOADER_ID;
    }

    /**
     * Cell点击的具体逻辑
     * @return true 代表我可以进行数据更新，你需要刷新，反之不能刷新
     */
    private boolean onItemSelectClick(Image image) {
        // 是否需要进行刷新
        boolean notifyRefresh;

        if (mSelectedImages.contains(image)) {
            mSelectedImages.remove(image);
            image.isSelect = false;
            // 状态已经改变，则需要通知更新
            notifyRefresh = true;
        } else {
            if (mSelectedImages.size() >= MAX_IMAGE_COUNT) {
                // 一个吐司提示
                // 得到提示文字
                String str = getResources().getString(R.string.label_gallery_select_max_size);
                // 格式化填充
                str = String.format(str,MAX_IMAGE_COUNT);
                Toast.makeText(getContext(), str, Toast.LENGTH_SHORT).show();
                notifyRefresh = false;
            } else {
                mSelectedImages.add(image);
                image.isSelect = true;
                notifyRefresh = true;
            }
        }
        // 如果数据有更改，那么我们需要通知外面的监听者我们的数据选中改变了
        if (notifyRefresh) {
            notifySelectChanged();
        }
        return true;

    }

    /**
     * 得到选中的图片的全部地址
     * @return 返回一个数组
     */
    public String[] getSelectedPath() {
        String[] filePaths = new String[mSelectedImages.size()];
        int index = 0;
        for (Image image : mSelectedImages) {
            filePaths[index++] = image.path;
        }
        return filePaths;
    }

    /**
     * 可以进行清空选中的图片
     */
    public void clear() {
        for (Image image : mSelectedImages) {
            // 一定要先重置状态
            image.isSelect = false;
        }
        mSelectedImages.clear();
        // 通知更新
        mAdapter.notifyDataSetChanged();
    }

    /**
     * 通知选中状态改变
     */
    private void notifySelectChanged () {
        // 得到监听者，并判断是否有监听者，然后进行回调
        SelectedChangedListener listener = mListener;
        if (listener != null) {
            listener.onSelectedCountChanged(mSelectedImages.size());
        }
    }

    /**
     * 通知Adapter数据更新的方法
     * @param images 新的数据
     */
    private void updateSource(List<Image> images) {
        mAdapter.replace(images);
    }

    /**
     * 用户用于实际的数据加载的Loader
     */
    private class LoaderCallback implements LoaderManager.LoaderCallbacks<Cursor> {
        private final String[] IMAGE_PROJECTION = new String[] {
                MediaStore.Images.Media._ID,
                MediaStore.Images.Media.DATA,
                MediaStore.Images.Media.DATE_ADDED
        };
        @NonNull
        @NotNull
        @Override
        public Loader<Cursor> onCreateLoader(int id, @Nullable @org.jetbrains.annotations.Nullable Bundle args) {
            // 创建一个Loader
            if (id == LOADER_ID) {
                Log.d(TAG, "onCreateLoader() called with: id = [" + id + "], args = [" + args + "]");
                // 如果是我们的id，则进行初始化
                return new CursorLoader(getContext(),
                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                                IMAGE_PROJECTION,
                                null,
                                null,
                        IMAGE_PROJECTION[2] + " DESC");// “DESC"倒叙查询

            }
                        return null;
        }

        @Override
        public void onLoadFinished(@NonNull @NotNull Loader<Cursor> loader, Cursor data) {
            // 当Loader加载完成时
            List<Image> images = new ArrayList<>();
            // 判断是否有数据
            if (data != null) {
                int count = data.getCount();
                if (count > 0) {
                    // 移动游标到开始
                    data.moveToFirst();

                    // 得到对应的列的坐标
                    int indexId = data.getColumnIndexOrThrow(IMAGE_PROJECTION[0]);
                    int indexPath = data.getColumnIndexOrThrow(IMAGE_PROJECTION[1]);
                    int indexDate = data.getColumnIndexOrThrow(IMAGE_PROJECTION[2]);
                    do {
                        // 循环读取，知道没有数据
                        int id = data.getInt(indexId);
                        String path = data.getString(indexPath);
                        long dateTime = data.getLong(indexDate);

                        File file = new File(path);
                        if (!file.exists() || file.length() < MIN_IMAGE_FILE_SIZE) {
                            // 如果图片太小或者没有图片，则跳过
                            continue;
                        }

                        // 添加一条新的图片数据
                        Image image = new Image();
                        image.id = id;
                        image.path = path;
                        image.date = dateTime;
                        images.add(image);

                    }while (data.moveToNext());
                }
            }
            updateSource(images);
        }

        @Override
        public void onLoaderReset(@NonNull @NotNull Loader<Cursor> loader) {
            // 当Loader销毁或者重置了,进行界面的清空操作
            updateSource(null);
        }
    }

    /**
     * 内部的数据结构，每一个数据结构都图片的属性
     */
    private static class Image {
        // 数据的ID
        int id;
        // 图片的路径
        String path;
        // 图片的创建日期
        long date;
        // 是否被选中
        boolean isSelect;

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            Image image = (Image) o;
            return Objects.equals(path, image.path);
        }

        @Override
        public int hashCode() {
            return Objects.hash(path);
        }
    }

    /**
     * 适配器
     */
    private class Adapter extends RecyclerAdapter<Image> {

        /**
         * 返回布局的id
         * @param position 坐标
         * @param image
         * @return
         */
        @Override
        protected int getItemViewType(int position, Image image) {
            return R.layout.cell_galley;
        }

        @Override
        protected ViewHolder<Image> onCreateViewHolder(View root, int viewType) {
            return new GalleryView.ViewHolder(root);
        }

    }

    /**
     * Cell对应的holder
     */
    private class ViewHolder extends RecyclerAdapter.ViewHolder<Image> {
        private ImageView mPic;
        private View mShade;
        private CheckBox mSelected;


        public ViewHolder(@NonNull @NotNull View itemView) {
            super(itemView);
            mPic = itemView.findViewById(R.id.iv_image);
            mShade = itemView.findViewById(R.id.view_shade);
            mSelected = itemView.findViewById(R.id.cb_select);
        }

        @Override
        protected void onBind(Image image) {
            // 加载图片
            Glide.with(getContext())
                    .load(image.path)   // 加路径
                    .diskCacheStrategy(DiskCacheStrategy.NONE)  // 不使用缓存，因为是本地图片
                    .centerCrop()   // 居中剪切
                    .placeholder(R.color.grey_200)  // 设置一个颜色，在图片还没有加载出来的时候显示的颜色
                    .into(mPic);
            Log.d(TAG, "onBind() called with: image = [" + image.path + "]");
            mShade.setVisibility(image.isSelect ? VISIBLE : INVISIBLE);
            mSelected.setChecked(image.isSelect);
            mSelected.setVisibility(View.VISIBLE);
        }

    }

    /**
     * 对外的一个监听器
     */
    public interface SelectedChangedListener {
        void onSelectedCountChanged(int count);
    }
}